import {AfterViewInit, Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges} from '@angular/core';
import {ITerminalOptions, Terminal} from 'xterm';
import {fit} from 'xterm/lib/addons/fit/fit';
import {SettingUrl} from '../../../public/setting/setting_url';
import {Setting} from '../../../public/setting/setting';
import {IdeService} from '../ide.service';

@Component({
  selector: 'app-terminal',
  templateUrl: './terminal.component.html',
  styleUrls: ['./terminal.component.scss']
})
export class TerminalComponent implements OnInit, OnDestroy, AfterViewInit, OnChanges {

  constructor(private el: ElementRef, private ideService: IdeService) {
  }
  @Input() showTerminal = false;
  @Input() resize: number;

  @Output() afterConnectClose = new EventEmitter();
  @Output() afterFileExecuteComplete = new EventEmitter();

  private terminalOptions: ITerminalOptions = {
    cursorBlink: true,
    scrollback: 3000,
    theme: {
      background: '#002938'
    }
  };
  private xterm = new Terminal(this.terminalOptions);
  private xtermDefaultString = '';
  private endString = 'EOF'; // END OF FILE
  private socketUrl = '';
  private ws: WebSocket;
  private newLine = '\r';

  /**
   * data submit
   * @param type：0(open)，1(send msg)，-1(close)
   * @param data
   */
  private static setSubmitData(type: number, data?: string) {
    let ret;
    switch (type) {
      case 0:
        ret = JSON.stringify({name: 'term.open', cmd: data}); // connect shell
        break;
      case 1:
        ret = JSON.stringify({name: 'term.input', cmd: data}); // shell data
        break;
      case -1:
        ret = JSON.stringify({name: 'term.exit', cmd: data}); // exit shell
        break;
    }
    return ret;
  }

  @HostListener('window:resize', ['$event']) OnResize() {
    if (this.xterm) { fit(this.xterm); }
  }

  /**
   * resize xterm after parent component size change
   * @param changes
   */
  ngOnChanges(changes: SimpleChanges): void {
    if (changes['resize'] && this.resize) {
      fit(this.xterm);
    }
  }

  ngOnInit(): void {
  }

  ngAfterViewInit() {
    this.openTerminal(); // open terminal
  }

  /**
   * open terminal in a container
   */
  private openTerminal() {
    const me = this;
    if (me.xterm) {
      me.xterm.open(me.el.nativeElement.querySelector('.terminal-container'));
      me.xterm.write(me.xtermDefaultString);
      fit(me.xterm);
    }
  }

  /**
   * clean xterm msgs
   */
  xtermClear() {
    this.xterm.clear();
    this.xterm.focus();
  }


  localWebsocket(data, callback?) {
    const me = this;
    if (data.cmd === 'start') { me.xtermClear(); }
    if (me.ws && me.ws.readyState === 0) {
      me.xterm.writeln(`\u001b[34m${Setting.I18nData['Ide0045']}\u001b[39m`); // drak blue
    } else if (me.ws && me.ws.readyState === 1) {
      if (data) { me.sendWs(JSON.stringify(data)); }
      if (typeof callback === 'function') { callback(); }
    } else {
      me.socketUrl = SettingUrl.URL.localApi.socket(this.ideService.deviceIp);
      me.ws = new WebSocket(this.socketUrl);
      me.ws.onopen = function () {
        me.xterm.focus();
        if (data) { me.sendWs(JSON.stringify(data)); }
        if (typeof callback === 'function') { callback(); }
      };

      me.ws.onmessage = function (event) {
        if (event.data.indexOf(me.endString) >= 0) { me.afterFileExecuteComplete.emit({finish: true}); } else { me.xterm.write(`${event.data}${me.newLine}`); }
        me.xterm.focus();
      };

      me.ws.onerror = function () {
        me.xtermDefaultString = '';
        me.afterFileExecuteComplete.emit({close: true});
        me.xterm.write(`${me.newLine}\u001b[31m${Setting.I18nData['Ide0050']}\u001b[39m`); // red
        me.xterm.write(`${me.newLine}`);
        me.xterm.focus();
      };

      me.ws.onclose = function () {
        me.xtermDefaultString = '';
        me.afterFileExecuteComplete.emit({close: true});
        me.xterm.write(`${me.newLine}\u001b[31m${Setting.I18nData['Ide0049']}\u001b[39m`); // red
        me.xterm.write(`${me.newLine}`);
      };
    }
  }

  sendWs(msg) {
    this.ws.send(msg);
  }

  closeWs(sshFailed: boolean = false) {
    const me = this;
    if (me.ws && sshFailed) {
      me.xterm.writeln(`\u001b[31mssh${Setting.I18nData['Ide0051']}\u001b[39m`); // red
      me.ws.close(); // 关闭socket连接
      me.afterConnectClose.emit(false);
    } else if (me.ws && me.ws.readyState === 0) {
      me.xterm.writeln(`\u001b[34m${Setting.I18nData['Ide0045']}\u001b[39m`); // drak blue
    } else if (me.ws && me.ws.readyState === 2) {
      me.xterm.write(`${me.newLine}\u001b[33m${Setting.I18nData['Ide0052']}\u001b[39m${me.newLine}${me.xtermDefaultString}`); // orange
    } else if (me.ws && me.ws.readyState === 3) {
      me.xterm.writeln(`\u001b[31m${Setting.I18nData['Ide0053']}\u001b[39m`); // red
    } else if (this.ws) {
      me.xterm.write(`${me.newLine}\u001b[33m${Setting.I18nData['Ide0054']}\u001b[39m`); // orange
      me.sendWs(TerminalComponent.setSubmitData(-1)); // close ssh
      me.ws.close(); // close socket
      me.afterConnectClose.emit(false);
    }
  }

  ngOnDestroy() {
    this.closeWs();
  }

}
